package top.tangyh.lamp.common.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;


import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import top.tangyh.basic.exception.BizException;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.Function;

/**
 * <p>
 * easyexcel工具
 * </p>
 *
 * @author:
 * @since:
 */
@Slf4j
@Component
public class EasyExcelUtil {
	private static EasyExcelUtil me;

	@PostConstruct
	public void init() {
		me = this;
	}

	public static void whriteNewBlankRow(ExcelWriter excelWriter, WriteSheet writeSheet, int colCount) {
		List<List<String>> totalListList = new ArrayList<List<String>>();
		List<String> totalList = new ArrayList<String>();
		totalListList.add(totalList);
		for (int i = 0; i <= colCount; i++) {
			totalList.add(null);
		}
		excelWriter.write(totalListList, writeSheet);
	}

	public static void whriteNewRowBy(ExcelWriter excelWriter, WriteSheet writeSheet, int colCount, List<String> totalList) {
		List<List<String>> totalListList = new ArrayList<List<String>>();
		totalListList.add(totalList);
		excelWriter.write(totalListList, writeSheet);
	}

	/**
	 * excel非模板导出工具
	 *
	 * @param response
	 * @param rstList   要导出的数据集
	 * @param voClass   要导出的数据集中 的记录格式
	 * @param sheetName 文件名主要部份
	 * @param colCount  列数，主要用在尾部添加统计信息
	 * @param totalList 尾部的统计行
	 * @param isRowNo   是否在首列显示行序号
	 */
	public static void writeToExcel(HttpServletResponse response, List rstList, Class voClass, String sheetName, int colCount, List<String> totalList, boolean isRowNo) {

		try {
			OutputStream excelOutputStream = getOutputStreamExportExcel(response, sheetName);
			ExcelWriter excelWriter = null;
			if (isRowNo) {
				excelWriter = EasyExcel.write(excelOutputStream, voClass)
						.autoCloseStream(Boolean.TRUE)
						.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
						.registerWriteHandler(new CustomRowWriteHandler())
						.build();
			} else {
				excelWriter = EasyExcel.write(excelOutputStream, voClass)
						.autoCloseStream(Boolean.TRUE)
						.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
						.build();
			}

			WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
			excelWriter.write(rstList, writeSheet);
			if (totalList != null && !totalList.isEmpty()) {
				EasyExcelUtil.whriteNewRowBy(excelWriter, writeSheet, colCount, totalList);
			}

			excelWriter.finish();
		} catch (Exception e) {
			me.log.error("导出报表出错 e : {}", e.toString());
			throw new BizException(sheetName + "导出失败");
		}
	}

	/**
	 * excel模板方式导出工具
	 *
	 * @param response
	 * @param rstList      要导出的数据集
	 * @param voClass      要导出的数据集中 的记录格式
	 * @param templateName 模板文件名
	 * @param sheetName    文件名主要部份
	 * @param colCount     列数，主要用在尾部添加统计信息
	 * @param totalList    尾部的统计行
	 */
	public static void writeToExcelByTempl(HttpServletResponse response, List rstList, Class voClass, String templateName, String sheetName, Map<String, Object> headMap, int colCount, List<String> totalList) {
		try {
			OutputStream excelOutputStream = getOutputStreamExportExcel(response, sheetName);
			ExcelWriter excelWriter = EasyExcel.write(excelOutputStream, voClass)
					.withTemplate(ResourceUtil.getStream(templateName))
					.build();
			WriteSheet writeSheet = EasyExcel.writerSheet().build();
			excelWriter.fill(rstList, writeSheet);
			if (headMap != null && !headMap.isEmpty()) {
				excelWriter.fill(headMap, writeSheet);
			}
			if (totalList != null && !totalList.isEmpty()) {
				EasyExcelUtil.whriteNewRowBy(excelWriter, writeSheet, colCount, totalList);
			}

			excelWriter.finish();
		} catch (Exception e) {
			me.log.error("导出报表出错 e : {}", e.toString());
			throw new BizException(sheetName + "导出失败");
		}
	}

	private static OutputStream getOutputStreamExportExcel(HttpServletResponse response, String sheetName) throws IOException {
		response.setContentType("application/vnd.ms-excel");
		response.setCharacterEncoding("utf-8");
		String fileName = URLEncoder.encode(sheetName + DateUtil.format(DateUtil.date(System.currentTimeMillis()), "yyyy年MM月dd日HH点mm分ss秒"), "UTF-8").replaceAll("\\+", "%20");
		response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
		response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
		return response.getOutputStream();

	}


	/**
	 * excel导入方法，T 为行对应的BEAN
	 *
	 * @param file
	 * @param rowVoClass ，每行对应的实体Bean
	 * @param sheetName  ，要处理的excel中的sheet名
	 * @param startRow ,开始行
	 * @param doFun      导入处理函数
	 * @return key:error返回出错，result:1--成功,0--失败
	 */
	public static <T> Map<String, Object> importExcel(MultipartFile file, Class rowVoClass, String sheetName, Integer startRow, Function<List<T>, Map<String, Object>> doFun) throws IOException {

		Map<String, Object> rst = new HashMap<>();
		String path = file.getOriginalFilename();
		String[] strs = path.split("\\.");
		if (strs.length <= 1) {
			rst.put("error", "文件类型不正确");
			rst.put("result", 0);
		}
		String fileType = strs[strs.length - 1];
		if (!fileType.equals("xls") && !fileType.equals("xlsx")) {
			rst.put("error", "文件类型不正确");
			rst.put("result", 0);
		}

		ExcelReaderBuilder excelReaderBuilder = EasyExcel.read(file.getInputStream(), rowVoClass, new ExcelListener(p -> {
			System.out.println();
			Map<String,Object> map =doFun.apply(p);
			if(CollectionUtil.isNotEmpty(map)) rst.putAll(map);
		}));
		startRow =startRow==null?2:startRow;
		if (StrUtil.isBlank(sheetName)) {
			excelReaderBuilder.sheet(sheetName).headRowNumber(startRow).doRead();
		} else {
			excelReaderBuilder.sheet().headRowNumber(startRow).doRead();
		}

		rst.put("result", 1);
		return rst;
	}


}